package sncf.client;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimerTask;
import java.util.regex.Pattern;

import sncf.server.SncfService;
import sncf.utils.AdminUtils;
import sncf.utils.ConfigLoader;
import sncf.utils.Referential;

public class ActionTask extends TimerTask {

	// FIELDS
	private SncfAlertView view;

	// CONSTRUCTORS
	public ActionTask(SncfAlertView view) {
		this.view = view;
	}

	@Override
	public void run() {
		try {
			System.out.println("");
			System.out.println("");
			System.out.println("==== START LOADING TASK ====");
			SncfService service = SncfService.getInstance();
			List<Train> trainList = service.getListTrain();
			handleResult(trainList);

			Boolean lateService = (Boolean) ConfigLoader.getInstance().get(
					ConfigLoader.LATE_CONFIRMATION_SERVICE_PROPERTY);
			boolean confirmServiceActivate = lateService != null ? lateService
					: false;

			if (confirmServiceActivate) {
				reportTrainListToConfirm();
			}
		} catch (Exception e) {
			e.printStackTrace();
			AdminUtils.notifySystemAdmin(e);
		} finally {
			Referential ref = Referential.getInstance();
			ConfigLoader configLoader = ConfigLoader.getInstance();

			System.out.println("==== END LOADING TASK ====");
			System.out.println("");

			SimpleDateFormat dayFormatter = new SimpleDateFormat("dd/MM/yyyy");
			SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm");

			Date nextSaveDate = ref.getNextDateSave();
			Date nextConfirmDate = ref.getNextConfirmDate();
			String workingDir = (String) configLoader
					.get(ConfigLoader.WORKING_DIR_PROPERTY);

			System.out.println("==== Prochaine sauvegarde prevue le "
					+ dayFormatter.format(nextSaveDate) + " a "
					+ timeFormatter.format(nextSaveDate) + " dans le dossier "
					+ workingDir + " ====");

			if (nextConfirmDate != null) {
				System.out
						.println("==== Prochaine confirmation des retards prevue le "
								+ dayFormatter.format(nextConfirmDate)
								+ " a "
								+ timeFormatter.format(nextConfirmDate)
								+ " ====");
			}
		}
	}

	private void reportTrainListToConfirm() {
		System.out.println("");
		System.out.println("===== [START] REMAINING TRAINS TO CONFIRM =====");
		try {
			Referential ref = Referential.getInstance();
			boolean dayFilterEnabled = false;
			Collection<Train> trainSetToConfirm = ref
					.getTrainSetToConfirm(dayFilterEnabled);

			if (trainSetToConfirm != null && !trainSetToConfirm.isEmpty()) {
				for (Train train : trainSetToConfirm) {
					System.out.println(train);
				}
			} else {
				System.out
						.println("Aucun train en attente de confirmation du temps de retard pour l'instant.");
			}
		} finally {
			System.out.println("===== [END] REMAINING TRAINS TO CONFIRM =====");
			System.out.println("");
		}
	}

	private void handleResult(List<Train> trainList) {
		this.view.refresh(trainList);

		// validateWorkingDirectory();

		List<Train> alertList = new ArrayList<Train>();
		final int maxMinutesLate = (Integer) ConfigLoader.getInstance().get(
				ConfigLoader.MAX_MINUTES_LATE_PROPERTY);

		if (trainList != null) {
			Set<Train> trainWithoutFilter = new HashSet<Train>();

			String lastKey = null;
			for (Train train : trainList) {
				if (lastKey == null || !lastKey.equals(train.getKey())) {
					System.out.println();
					System.out.println("===== Trains arrivant a "
							+ train.getTo() + " =====");
					lastKey = train.getKey();
				}
				System.out.println(train);

				int minutesLate = train.getMinutesLate();
				if (minutesLate >= maxMinutesLate
						|| (train.getSituation() != null && train
								.getSituation().toLowerCase()
								.contains("supprim"))) {
					trainWithoutFilter.add(train);

					Map<String, List<String>> fromFilterMap = (Map<String, List<String>>) ConfigLoader
							.getInstance().get(
									ConfigLoader.FROM_FILTER_PROPERTY);
					List<String> fromListFilter = fromFilterMap.get(train
							.getKey());

					Map<String, List<String>> trainNumberFilterMap = (Map<String, List<String>>) ConfigLoader
							.getInstance().get(
									ConfigLoader.TRAIN_NUMBER_FILTER_PROPERTY);
					List<String> trainNumberListFilter = trainNumberFilterMap
							.get(train.getKey());

					if ((fromListFilter == null || fromListFilter
							.contains(train.getFrom().replaceAll(" ", "")
									.toLowerCase()))
							&& (trainNumberListFilter == null || trainNumberMatchFilter(
									trainNumberListFilter, train.getNumber()
											.toLowerCase()))) {
						alertList.add(train);
					}
				}
			}
			System.out.println("");
			System.out.println("==== LISTE ALERTE SANS FILTRE [DEBUT]====");
			for (Train train : trainWithoutFilter) {
				System.out.println(train);
			}
			System.out.println("==== LISTE ALERTE SANS FILTRE [FIN]====");
			processAlert(alertList, trainList);
		}
	}

	private boolean trainNumberMatchFilter(List<String> trainNumberListFilter,
			String trainNumber) {
		boolean match = true;

		if (trainNumberListFilter != null) {
			int size = trainNumberListFilter.size();
			int i = 0;
			while (i < size && match) {
				String regex = trainNumberListFilter.get(i);
				match = Pattern.matches(regex, trainNumber);
				i++;
			}
		}

		return match;
	}

	private void processAlert(List<Train> trainList,
			List<Train> originalTrainList) {
		if (trainList != null) {
			System.out.println("");
			System.out.println("===== NOUVEAUX TRAINS EN ALERTE ======");
			Referential ref = Referential.getInstance();
			for (Train train : trainList) {
				if (!ref.isTrainStored(train)) {
					System.out.println(train);
					ref.addAlertTrain(train);
				} else {
					ref.UpdateTrain(train);
				}
			}
			System.out.println("===== FIN NOUVEAUX TRAINS EN ALTERTE ======");

			ref.removeOldTAlertTrains(trainList, originalTrainList);

			trainList.clear();

			System.out.println("");
			System.out.println("====== ETAT ACTUEL DES ALERTES [DEBUT] ======");
			Collection<Train> alertTrains = ref.getAlertTrains();
			if (alertTrains.isEmpty()) {
				System.out.println("Aucun train en alerte pour l'instant.");
			} else {
				for (Train train : alertTrains) {
					System.out.println(train);
				}
			}
			System.out.println("====== ETAT ACTUEL DES ALERTES [FIN] ======");
		}
	}

}
